home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 17 / CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso / CUCD / Programming / DiceSource / src / vmake / reader.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-09-09  |  16.2 KB  |  475 lines

  1. /*
  2.  *    (c)Copyright 1992-1997 Obvious Implementations Corp.  Redistribution and
  3.  *    use is allowed under the terms of the DICE-LICENSE FILE,
  4.  *    DICE-LICENSE.TXT.
  5.  */
  6. #include "vmake.h"
  7.  
  8. Prototype int get_simple_token(char *buf);
  9. Prototype int get_token(char *buf1, char *buf2, char *buf3);
  10. Prototype struct G_OBJECT **newobj(struct G_OBJECT **objlist, int class, char *buf);
  11. Prototype int parse_config(char *cfname);
  12. Prototype int init_config(char *cfname);
  13. Prototype void close_config(void);
  14.  
  15. #define MAX_STRTOK     128    /* The largest string we allow for a string token */
  16. /*********************************************************************
  17.  * TOKENS:
  18.  *      TOK_EOF     End of file
  19.  *                  '/''*' '*''/'
  20.  *      TOK_STRING  "string"
  21.  *      TOK_STRING  'string'
  22.  *      TOK_BAR     BAR
  23.  *      TOK_TEXT    TEXT   <string> <string>
  24.  *      TOK_CONFIG  CONFIG <string> <string>
  25.  *      TOK_SUBRTN  SUBRTN <string> <string>
  26.  *      TOK_BUTTON  BUTTON <string> <string>
  27.  *      TOK_CHECK   CHECK  <string> <string> <string>
  28.  *      TOK_CYCLE   CYCLE  <string>
  29.  *      TOK_ITEM    ITEM   <string> <string>
  30.  *      TOK_LIST    LIST   <string> <string> <string>
  31.  *      TOK_MENU    MENU   <string>
  32.  *      TOK_STRING  STRING <string> <string>
  33.  *      TOK_TITLE   TITLE  <string>
  34.  *      TOK_VALUE   VALUE  <string> <string>
  35.  */
  36. #define TOK_ERROR  -1
  37. #define TOK_EOF     0 /* Note ordering of ERROR/EOF is assumed for easy tests below */
  38. #define TOK_STRTOK  1
  39. #define TOK_TOKEN   2
  40. #define TOK_BAR     3
  41. #define TOK_BUTTON  4
  42. #define TOK_CHECK   5
  43. #define TOK_CYCLE   6
  44. #define TOK_ITEM    7
  45. #define TOK_LIST    8
  46. #define TOK_MENU    9
  47. #define TOK_STRING 10
  48. #define TOK_TITLE  11
  49. #define TOK_VALUE  12
  50. #define TOK_TEXT   13
  51. #define TOK_CONFIG 14
  52. #define TOK_SUBRTN 15
  53.  
  54. struct TOK_LOOK {
  55.    char toktype;   /* Value to return for this token                        */
  56.    char token[6];  /* Note that we only allow 6 characters in a token       */
  57.    char strings;   /* Number of strings that the token takes as an argument */
  58. };
  59.  
  60. struct TOK_LOOK tokens[] = {
  61.    { TOK_BAR,     "BAR   ", 0},
  62.    { TOK_BUTTON,  "BUTTON", 2},
  63.    { TOK_CHECK,   "CHECK ", 3},
  64.    { TOK_CYCLE,   "CYCLE ", 1},
  65.    { TOK_ITEM,    "ITEM  ", 3},
  66.    { TOK_LIST,    "LIST  ", 2},
  67.    { TOK_MENU,    "MENU  ", 1},
  68.    { TOK_STRING,  "STRING", 2},
  69.    { TOK_TITLE,   "TITLE ", 1},
  70.    { TOK_VALUE,   "VALUE ", 2},
  71.    { TOK_TEXT,    "TEXT  ", 2},
  72.    { TOK_CONFIG,  "CONFIG", 2},
  73.    { TOK_SUBRTN,  "SUBRTN", 2},
  74. };
  75. #define MAX_LOOK (sizeof(tokens)/sizeof(struct TOK_LOOK))
  76.  
  77. /*********************************************************************
  78.  * Character classes:
  79.  *  0  CL_EOF    - EOF
  80.  *  1  CL_SLASH  - /
  81.  *  2  CL_STAR   - *
  82.  *  3  CL_DQUOTE - "
  83.  *  4  CL_SQUOTE - '
  84.  *  5  CL_ALPHA  - A-Z a-z
  85.  *  6  CL_BLANK  - ' ' \t \n
  86.  *  7  CL_OTHER  - Anything else
  87.  */
  88. #define CL_EOF     0
  89. #define CL_SLASH   1
  90. #define CL_STAR    2
  91. #define CL_DQUOTE  3
  92. #define CL_SQUOTE  4
  93. #define CL_ALPHA   5
  94. #define CL_BLANK   6
  95. #define CL_OTHER   7
  96. #define MAX_CL     8
  97.  
  98. /*********************************************************************
  99.  * States:
  100.  *  0  ST_SCN - SCAN   - Scanning - Looking for any character - skipping white space
  101.  *  1  ST_GSL - GOTSL  - Found /  - Checking for a matching * to start a comment
  102.  *  2  ST_CMT - CMT    - Comment  - Looking for a * to close a comment
  103.  *  3  ST_GST - GOTST  - Found *  - Checking for a / to close a comment
  104.  *  4  ST_DQT - DQUOTE - String " - Looking for a matching "
  105.  *  5  ST_SQT - SQUOTE - String ' - Looking for a matching '
  106.  *  6  ST_TOK - TOKEN  - Token    - Gathering a keyword token
  107.  */
  108. #define ST_SCN  0
  109. #define ST_GSL  1
  110. #define ST_CMT  2
  111. #define ST_GST  3
  112. #define ST_DQT  4
  113. #define ST_SQT  5
  114. #define ST_TOK  6
  115. #define MAX_ST 7
  116. #define MASK_ST 7
  117.  
  118. /*********************************************************************
  119.  * State Table Transitions:
  120.  *
  121.  *            Character Class
  122.  *            0-EOF   1-/      2-*      3-"      4-'      5-A-Z      6-Blank  7-Other
  123.  *   State
  124.  *   0 SCAN    END    GOTSL   ERROR    DQUOTE   SQUOTE    >TOKEN     SCAN     ERROR
  125.  *   1 GOTSL  ERROR   ERROR   CMT      ERROR    ERROR     ERROR      ERROR    ERROR
  126.  *   2 CMT    ERROR   CMT     GOTST    CMT      CMT       CMT        CMT      CMT
  127.  *   3 GOTST  ERROR   SCAN    CMT      CMT      CMT       CMT        CMT      CMT
  128.  *   4 DQUOTE ERROR   >DQUOTE >DQUOTE  !SCAN    >DQUOTE   >DQUOTE    >DQUOTE  >DQUOTE
  129.  *   5 SQUOTE ERROR   >SQUOTE >SQUOTE  >SQUOTE  !SCAN     >SQUOTE    >SQUOTE  >SQUOTE
  130.  *   6 TOKEN  +END    +GOTSL  ERROR    +DQUOTE  +SQUOTE   >TOKEN     +SCAN    ERROR
  131.  * Note: >     - AC_SAV - Means to append the current character and continue scan
  132.  *       !     - AC_STR - Means to return the current token as a string.
  133.  *       +     - AC_TOK - Means to return the current token as a keyword
  134.  *       ERROR - AC_ERR - Indicates issuing an error
  135.  *       END   - AC_END - Indicates returing the END token.
  136.  */
  137. #define AC_SKP (0<<5) /* Must be zero - the default to do nothing */
  138. #define AC_SAV (1<<5)
  139. #define AC_STR (2<<5)
  140. #define AC_TOK (3<<5)
  141. #define AC_ERR (4<<5)
  142. #define AC_END (5<<5)
  143. #define MASK_AC (7<<5)
  144.  
  145. char statetab[MAX_ST][MAX_CL] =
  146. {
  147. /* 0 ST_SCN  */
  148.    { AC_END,        ST_GSL,         AC_ERR,         ST_DQT,
  149.      ST_SQT,        AC_SAV|ST_TOK,  ST_SCN,         AC_ERR         },
  150. /* 1 ST_GSL */
  151.    { AC_ERR,        AC_ERR,         ST_CMT,         AC_ERR,
  152.      AC_ERR,        AC_ERR,         AC_ERR,         AC_ERR         },
  153. /* 2 ST_CMT   */
  154.    { AC_ERR,        ST_CMT,         ST_GST,         ST_CMT,
  155.      ST_CMT,        ST_CMT,         ST_CMT,         ST_CMT         },
  156. /* 3 ST_GST */
  157.    { AC_ERR,        ST_SCN,         ST_CMT,         ST_CMT,
  158.      ST_CMT,        ST_CMT,         ST_CMT,         ST_CMT         },
  159. /* 4 ST_DQT*/
  160.    { AC_ERR,        AC_SAV|ST_DQT,  AC_SAV|ST_DQT,  AC_STR|ST_SCN,
  161.      AC_SAV|ST_DQT, AC_SAV|ST_DQT,  AC_SAV|ST_DQT,  AC_SAV|ST_DQT  },
  162. /* 5 ST_SQT*/
  163.    { AC_ERR,        AC_SAV|ST_SQT,  AC_SAV|ST_SQT,  AC_SAV|ST_SQT,
  164.      AC_STR|ST_SCN, AC_SAV|ST_SQT,  AC_SAV|ST_SQT,  AC_SAV|ST_SQT  },
  165. /* 6 ST_TOK */
  166.    { AC_TOK|ST_SCN, AC_TOK|ST_GSL,  AC_ERR,         AC_TOK|ST_DQT,
  167.      AC_TOK|ST_SQT, AC_SAV|ST_TOK,  AC_TOK|ST_SCN,  AC_ERR         },
  168. };
  169.  
  170. /*
  171.  * Get a simple token from the file.
  172.  * No parsing of semantics is done at this level.
  173.  */
  174. int get_simple_token(char *buf)
  175. {
  176.    int c;
  177.    int pos;
  178.    int class;
  179.    int action;
  180.  
  181.    pos = 0;
  182.  
  183.    for(;;)
  184.    {
  185.       /* Get the next character from the input file and assign a character class */
  186.       c = getc(global.fp);
  187.       class = CL_OTHER;
  188.       switch(c)
  189.       {
  190.          case EOF:  class = CL_EOF;    break;
  191.          case '/':  class = CL_SLASH;  break;
  192.          case '*':  class = CL_STAR;   break;
  193.          case '"':  class = CL_DQUOTE; break;
  194.          case '\'': class = CL_SQUOTE; break;
  195.          case '\n': global.line++;
  196.          case ' ':
  197.          case '\t':  class = CL_BLANK;  break;
  198.          default:
  199.             if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
  200.                class = CL_ALPHA;
  201.             break;
  202.       }
  203.       /* Run us through the state table to get an action and a new state */
  204.       action = statetab[global.state][class];
  205.       global.state = (action & MASK_ST);
  206.  
  207.       /* Perform the work for the action */
  208.       switch(action & MASK_AC)
  209.       {
  210.          case AC_SAV: if (pos < MAX_STRTOK) /* make sure we don't overflow the buffer */
  211.                       {
  212.                          buf[pos++] = c;  /* Save the character */
  213.                          break;
  214.                       }
  215.                       /* Else fall through to the error case */
  216.          case AC_ERR: return(TOK_ERROR);
  217.          case AC_STR: buf[pos] = 0;   /* Null terminate what we gathered */
  218.                       return(TOK_STRTOK);
  219.          case AC_TOK: buf[pos] = 0;
  220.                       return(TOK_TOKEN);
  221.          case AC_END: return(TOK_EOF);
  222.       }
  223.    }
  224. }
  225.  
  226. /*
  227.  * Get the next token and any associated strings.
  228.  */
  229. int get_token(char *buf1,
  230.               char *buf2,
  231.               char *buf3
  232.              )
  233. {
  234.    int i;
  235.    int j;
  236.    int toktype;
  237.    int len;
  238.    char *strs[3];
  239.  
  240.    strs[0] = buf1;
  241.    strs[1] = buf2;
  242.    strs[2] = buf3;
  243.  
  244.    toktype = get_simple_token(buf1);
  245.    if (toktype == TOK_EOF)   return(toktype);
  246.    if (toktype != TOK_TOKEN) return(TOK_ERROR);
  247.  
  248.    /* Go through and uppercase the string */
  249.    /* we KNOW that it consists of only upper/lower case letters */
  250.    len = strlen(buf1);
  251.    if (len > 6) return(TOK_ERROR);
  252.    strcpy(buf1+len, "     "); /* Make sure we blank pad for the memcmp */
  253.    for(i = 0; i < 6; i++)
  254.       if (buf1[i] >= 'a') buf1[i] -= ('a'-'A');
  255.  
  256.    /* Now go through the table and look for a token */
  257.    for (i = 0; i < MAX_LOOK; i++)
  258.       if (!memcmp(buf1, tokens[i].token, 6)) break;
  259.    if (i == MAX_LOOK) return(TOK_ERROR);
  260.  
  261.    /* We have a matching token, get any strings that it wants */
  262.    for(j = 0; j < tokens[i].strings; j++)
  263.    {
  264.       toktype = get_simple_token(strs[j]);
  265.       if (toktype != TOK_STRTOK) return(TOK_ERROR);
  266.    }
  267.  
  268.    /* Everything checks out, let them know what type of token they got */
  269.    return((int)tokens[i].toktype);
  270. }
  271.  
  272. void init_group(struct G_OBJECT *object)
  273. {
  274.    while(object != NULL)
  275.    {
  276.       if (object->next) object->next->prev = object;
  277.       if (object->class == CLASS_CYCLE)
  278.       {
  279.          struct G_VALUE *val;
  280.          struct G_CYCLE *cyc;
  281.  
  282.          cyc = (struct G_CYCLE *)object;
  283.  
  284.          cyc->curval = cyc->values;
  285.          for(val = cyc->curval; val; val = val->next)
  286.          {
  287.             if (cyc->base.next) cyc->base.next->prev = (struct G_OBJECT *)cyc;
  288.          }
  289.       }
  290.       object = object->next;
  291.    }
  292. }
  293. /*
  294.  * Allocate an object structure to hold an entry
  295.  */
  296. static short sizetab[] = { 0,
  297.                           sizeof(struct G_STRING),
  298.                           sizeof(struct G_CYCLE),
  299.                           sizeof(struct G_CHECK),
  300.                           sizeof(struct G_LIST),
  301.                           sizeof(struct G_BUTTON)
  302.                          };
  303.  
  304. struct G_OBJECT **newobj(struct G_OBJECT **objlist,
  305.                          int class,
  306.                          char *buf
  307.                         )
  308. {
  309.    struct G_OBJECT *obj;
  310.    obj = get_mem(sizetab[class]);
  311.    if (obj == NULL) return(NULL);
  312.  
  313.    if (objlist) *objlist = obj;
  314.    obj->class = class;
  315.    obj->title = savestr(buf);
  316.    return(&obj->next);
  317. }
  318.  
  319. /*
  320.  * Parse the configuration file (name is cfname)
  321.  * return:  0 if OK
  322.  *          1 if syntax error in config file
  323.  *          2 if unable to open config file
  324.  */
  325. int parse_config(char *cfname)
  326. {
  327.    static char buf1[MAX_STRTOK+2], buf2[MAX_STRTOK+2], buf3[MAX_STRTOK+2];
  328.    int toktype;
  329.    int menupos;
  330.    int buttonpos;
  331.    int strpos;
  332.    struct G_OBJECT **objlist;
  333.    struct G_VALUE  **valent;
  334.  
  335.    objlist = &global.objects;
  336.    valent = NULL;
  337.  
  338.    menupos = buttonpos = 0;
  339.    if (init_config(cfname)) return(2);
  340.  
  341.    while((toktype = get_token(buf1, buf2, buf3)) > TOK_EOF)
  342.    {
  343.       switch(toktype)
  344.       {
  345.          case TOK_TEXT:   strpos = atoi(buf1) - 1;
  346.                           if ((strpos < 0) || (strpos >= NUM_TEXT)) goto error;
  347.                           global.text[strpos] = savestr(buf2);
  348.                           break;
  349.          case TOK_CONFIG: strpos = atoi(buf1) - 1;
  350.                           if ((strpos < 0) || (strpos >= NUM_CONFIG)) goto error;
  351.                           global.text[CONFIG_BASE+strpos] = savestr(buf2);
  352.                           break;
  353.          case TOK_SUBRTN: strpos = atoi(buf1) - 1;
  354.                           if ((strpos < 0) || (strpos >= NUM_SUBRTN)) goto error;
  355.                           global.text[SUBRTN_BASE+strpos] = savestr(buf2);
  356.                           break;
  357.          case TOK_BAR:    global.menuitem[menupos].nm_Type   = MENU_ITEM;
  358.                           global.menuitem[menupos].nm_Label  = NM_BARLABEL;
  359.                           if (menupos >= MAX_MENU) goto error;
  360.                           menupos++;
  361.                           break;
  362.          case TOK_MENU:   global.menuitem[menupos].nm_Type   = MENU_MENU;
  363.                           global.menuitem[menupos].nm_Label  = savestr(buf1);
  364.                           if (menupos >= MAX_MENU) goto error;
  365.                           menupos++;
  366.                           break;
  367.          case TOK_ITEM:   global.menuitem[menupos].nm_Type   = MENU_ITEM;
  368.                           global.menuitem[menupos].nm_Label  = savestr(buf1);
  369.                           if (buf2[0])
  370.                              global.menuitem[menupos].nm_CommKey = savestr(buf2);
  371.                           global.menuitem[menupos].nm_UserData = savestr(buf3);
  372.                           if (menupos >= MAX_MENU) goto error;
  373.                           menupos++;
  374.                           break;
  375.          case TOK_BUTTON: if (buttonpos >= MAX_BUTTON) goto error;
  376.                           global.button[buttonpos].base.title = savestr(buf1);
  377.                           global.button[buttonpos++].command    = savestr(buf2);
  378.                           break;
  379.          case TOK_TITLE:  buf1[MAX_TITLE-1] = 0;
  380.                           strcpy(global.title2, buf1);
  381.                           break;
  382.          case TOK_STRING: objlist = newobj(objlist, CLASS_STRING, buf1);
  383.                           if (!objlist) goto error;
  384.                           ((struct G_STRING *)objlist)->option = savestr(buf2);
  385.                           valent = NULL;
  386.                           break;
  387.          case TOK_CHECK:  objlist = newobj(objlist, CLASS_CHECK, buf1);
  388.                           if (!objlist) goto error;
  389.                           ((struct G_CHECK *)objlist)->option0 = savestr(buf2);
  390.                           ((struct G_CHECK *)objlist)->option1 = savestr(buf3);
  391.                           valent = NULL;
  392.                           break;
  393.          case TOK_LIST:   objlist = newobj(objlist, CLASS_LIST, buf1);
  394.                           if (!objlist) goto error;
  395.                           ((struct G_LIST *)objlist)->option = savestr(buf2);
  396.                           if (!stricmp(buf2, "Files"))
  397.                              global.filelist = (struct G_LIST *)objlist;
  398.                           valent = NULL;
  399.                           break;
  400.          case TOK_CYCLE:  objlist = newobj(objlist, CLASS_CYCLE, buf1);
  401.                           if (!objlist) goto error;
  402.                           valent = &((struct G_CYCLE *)objlist)->values;
  403.                           break;
  404.          case TOK_VALUE:  if (valent == NULL) goto error;
  405.                           *valent = get_mem(sizeof(struct G_VALUE));
  406.                           if (!*valent) goto error;
  407.                           (*valent)->next = NULL;
  408.                           (*valent)->title = savestr(buf1);
  409.                           (*valent)->option = savestr(buf2);
  410.                           (*valent)->string = NULL;
  411.                           if (strchr(buf2, '%'))
  412.                           {
  413.                              struct G_STRING *gstr;
  414.  
  415.                              gstr = get_mem(sizeof(struct G_STRING));
  416.                              if (!gstr) goto error;
  417.                              gstr->base.class = CLASS_STRING;
  418.                              (*valent)->string = gstr;
  419.                           }
  420.                           valent = &((*valent)->next);
  421.                           break;
  422.       }
  423.    }
  424.    global.menuitem[menupos].nm_Type = MENU_END;
  425.  
  426.    if (toktype == TOK_ERROR)
  427.    {
  428. error:
  429.       sprintf(global.title, "ERROR- %s line %d", cfname, global.line);
  430.       global.objects = NULL; /* memory will get cleaned up on exit */
  431.       /* global.menuitem gets cleared in vmake.c to handle case of */
  432.       /* failure to open config file as well.                      */
  433.       return(1);
  434.    }
  435.    close_config();
  436.  
  437.    /* Now we need to go through the groups and sanitize the pointers as well */
  438.    /* as initialize all the default states                                   */
  439.    init_group(global.objects);
  440.    return(0);
  441. }
  442.  
  443. /*
  444.  * Open the configuration file and initialize any global data
  445.  */
  446. int init_config(char *cfname)
  447. {
  448.    struct Process *mytask;
  449.    APTR saveptr;
  450.  
  451.    global.state = ST_SCN;
  452.    global.line  = 1;
  453.    mytask = (struct Process *)FindTask(NULL);
  454.    saveptr = mytask->pr_WindowPtr;
  455.    mytask->pr_WindowPtr = (APTR)-1;
  456.    global.fp = fopen(cfname, "r");
  457.    mytask->pr_WindowPtr = saveptr;
  458.    if (global.fp == NULL)
  459.    {
  460.       sprintf(global.title, "ERROR- No %s", cfname);
  461.       return(1);
  462.    }
  463.    return(0);
  464. }
  465.  
  466. /*
  467.  * Close the configuration file and clean up anything else necessary
  468.  */
  469. void close_config()
  470. {
  471.    if (global.fp)
  472.       fclose(global.fp);
  473.    global.fp = NULL;
  474. }
  475.